home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
322_01
/
btree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-08-04
|
15KB
|
831 lines
/***
* module name:
btree.c
* function:
Provide a library of routines for creating and manipulating
B-Trees. The "order" of the B-Tree is controlled by a manifest
constant.
This module runs stand-alone with a dummy main program
if the symbol STAND_ALONE is defined.
* interface routines:
BTREE
Insert(dtm, tree) Insert DATUM dtm into B-tree "tree",
returning a reference to the updated
tree.
BTREE
Delete(key, tree) Remove the entry associated with "key"
from the B-Tree. Returns a reference
to the updated tree.
DATUM *
Search(key, tree) Look for key "key" in B-tree "tree".
Return a reference to the matching
DATUM if found, else NULL.
Apply(t, func) Applies function "func" to every cell
in the B-Tree -- uses an inorder
traversal.
* libraries used:
standard
* compile time parameters:
cc -O -c btree.c
* history:
Richard Hellier, University of Kent at Canterbury,
working from "Algorithms+Data Structures = Programs"
by N.Wirth -- also, "Data Structures and Program Design" by B.Kruse
Pub. Prentice-Hall.
Modified for use in dynamic memory allocation leak trace tool
by Mike Schwartz, 3-20-87. We call mmalloc and ffree instead of
malloc and free here, since malloc and free call this btree package
in the dynamic memory allocation leak detection package.
***/
#include "btree.h"
DATUM NullDatum = {
(char *) NULL,
};
static BTREE NewNode;
/*
** ERROR -- Print an error message
**
** Write the error text to the
** standard error stream.
**
** Parameters:
** fmt -- Printf-style format string
** arg[1-3] -- Arguments as needed.
**
** Returns:
** None.
**
*/
/* ARGSUSED */
Error(fmt, arg1, arg2, arg3)
char *fmt;{
fprintf(stderr, fmt, arg1, arg2, arg3);
}
/*
** KEYCMP -- Compare two key values
**
** Like "strcmp" but use key
** values rather than strings.
**
** Parameters:
** key1 -- First key,
** key2 -- Second key.
**
** Returns:
** -1 if key1 < key2;
** 0 if key1 = key2;
** 1 if key1 > key2;
**
*/
KeyCmp(key1, key2)
KEY key1,
key2;{
return key1 < key2 ? -1 : key1 == key2 ? 0 : 1;
}
/*
** SHOWDATUM -- Display a datum
**
** Atomic routine used to display
** the contents of a datum.
**
** Parameters:
** datum -- Datum to print.
**
** Returns:
** None.
**
*/
ShowDatum(dtm)
DATUM dtm;{
printf("\tkey x%x: callnum %d, size %d\n", dtm.key, dtm.inf.MalCallNum,
dtm.inf.MalSize);
}
/*
** MKNODE -- Make a new B-tree node
**
** Allocate storage for a new B-tree node
** and copy in some pointers.
**
** Parameters:
** k1 -- First key value,
** p0 -- First ptr,
** p1 -- Second ptr.
**
** Returns:
** Reference to the new node.
**
*/
BTREE
MkNode(dtm, p0, p1)
DATUM dtm;
BTREE p0,
p1;{
char *mmalloc();
BTREE t;
t = (BTREE) mmalloc(sizeof(NODE));
t -> t_ptr [0] = p0;
t -> t_ptr [1] = p1;
t -> t_dat [0] = dtm;
t -> t_active = 1;
return t;
}
/*
** DISPOSE -- Dispose of a tree node
**
** Return the storage occupied by the
** tree node to the pool.
**
** Parameters:
** t -- Ptr to the tree node.
**
** Returns:
** None.
**
*/
Dispose(t)
BTREE t;{
ffree((char *) t);
}
/*
** INSINNODE -- Add a key to a node
**
** Add a key value into a
** B-tree node. Splitting of
** nodes is handled elsewhere.
**
** Parameters:
** t -- Ptr to the node,
** key -- Key value to enter,
** ptr -- Link to subordinate node.
**
** Returns:
** None.
**
*/
InsInNode(t, d, ptr)
BTREE t,
ptr;
DATUM d;{
int i;
for ( i = t -> t_active; i > 0 && KeyCmp(d . key, t -> t_dat [i-1] . key) < 0; i--) {
t -> t_dat [i] = t -> t_dat [i - 1];
t -> t_ptr [i + 1] = t -> t_ptr [i];
}
t -> t_active++;
t -> t_dat [i] = d;
t -> t_ptr [i+1] = ptr;
}
/*
** INTERNALINSERT -- Key insert routine proper
**
** The business end of the key insertion
** routine.
**
** Parameters:
** key -- Key to insert,
** t -- Tree to use.
**
** Returns:
** Value of the key inserted.
**
*/
DATUM
InternalInsert(dtm, t)
DATUM dtm;
BTREE t;{
int i,
j;
DATUM ins;
BTREE tmp;
if (t == NULL) {
NewNode = NULL;
return dtm;
} else {
for (i = 0; i < t -> t_active && KeyCmp(t -> t_dat [i] . key, dtm . key) < 0; ++i)
; /* NULL BODY */
if (i < t -> t_active && KeyCmp(dtm . key, t -> t_dat [i] . key) == 0)
fprintf(stderr, "Already had it!\n");
else {
ins = InternalInsert(dtm, t -> t_ptr [i]);
if (KeyCmp(ins . key, NullDatum . key) != 0)
if (t -> t_active < 2 * M)
InsInNode(t, ins, NewNode);
else {
if (i <= M) {
tmp = MkNode(t -> t_dat [2 * M - 1], (BTREE) NULL, t -> t_ptr [2 * M]);
t -> t_active--;
InsInNode(t, ins, NewNode);
} else
tmp = MkNode(ins, (BTREE) NULL, NewNode);
/*
* Move keys and pointers ...
*/
for (j = M + 2; j <= 2 * M; ++j)
InsInNode(tmp, t -> t_dat [j-1], t -> t_ptr [j]);
t -> t_active = M;
tmp -> t_ptr [0] = t -> t_ptr [M+1];
NewNode = tmp;
return t -> t_dat [M];
}
}
return NullDatum;
}
}
/*
** INSERT -- Put a key into the B-tree
**
** Enter the given key into the
** B-tree.
**
** Parameters:
** key -- Key value to enter.
**
** Returns:
** Reference to the new B-tree.
**
*/
BTREE
Insert(dtm, t)
DATUM dtm;
BTREE t;{
DATUM ins;
ins = InternalInsert(dtm, t);
/*
* Did the root grow ?
*/
return KeyCmp(ins . key, NullDatum . key) != 0 ? MkNode(ins, t, NewNode) : t;
}
/*
** DELETE -- Remove a key from a B-tree
**
** Remove the data associated with a
** given key from a B-tree.
**
** Parameters:
** key -- Key to use,
** t -- B-tree to update.
**
** Returns:
** Reference to the updated B-tree.
**
** Notes:
** Real work is done by RealDelete() q.v.
**
*/
static int hadit = FALSE;
BTREE
Delete(key, t)
KEY key;
BTREE t;{
BTREE savet;
RealDelete(key, t);
if (!hadit) {
Error("No such key\n");
return NULL;
} else if (t -> t_active == 0) { /* Root is now empty */
savet = t -> t_ptr [0];
Dispose(t);
return savet;
} else
return t;
}
/*
** SEARCHNODE -- Find a key in a node
**
** Look for a key in a single B-tree
** node.
**
** Parameters:
** key -- Key to look for,
** t -- Ptr to B-tree node.
**
** Returns:
** Index of matching key.
**
*/
int
SearchNode(key, t)
KEY key;
BTREE t;{
int i;
if (KeyCmp(key, t -> t_dat [0] . key) < 0) {
hadit = FALSE;
return 0;
} else {
for (i = t -> t_active; KeyCmp(key, t -> t_dat [i-1] . key) < 0 && i > 1; --i)
; /* NULL BODY */
hadit = (KeyCmp(key, t -> t_dat [i-1] . key) == 0);
return i;
}
}
/*
** REALDELETE -- Remove a key from a tree
**
** The business end of the Delete() function.
**
** Parameters:
** key -- Key to use,
** t -- Tree to update.
**
** Returns:
** None.
**
*/
RealDelete(key, t)
KEY key;
BTREE t;{
int k;
if (t == NULL)
hadit = FALSE;
else {
k = SearchNode(key, t);
if (hadit) {
if (t -> t_ptr [k-1] == NULL) /* A leaf */
Remove(t, k);
else {
Succ(t, k);
RealDelete(t -> t_dat [k-1] . key, t -> t_ptr [k]);
if (!hadit)
Error("Hmm ???");
}
} else {
RealDelete(key, t -> t_ptr [k]);
if (t -> t_ptr [k] != NULL && t -> t_ptr [k] -> t_active < M)
Restore(t, k);
}
}
}
/*
** REMOVE -- Remove a single datum
**
** Remove a datum from a B-tree node
** by shuffling down the pointers and
** data above it.
**
** Parameters:
** t -- Ptr to the B-tree node,
** pos -- Index of the key to be removed.
**
** Returns:
** None.
**
*/
Remove(t, pos)
BTREE t;
int pos;{
int i;
for (i = pos + 1; i <= t -> t_active; ++i) {
t -> t_dat [i-2] = t -> t_dat [i-1];
t -> t_ptr [i-1] = t -> t_ptr [i];
}
t -> t_active--;
}
/*
** SUCC -- Replace a key by its successor
**
** Using the natural ordering, replace
** a key wit